package com.beijiteshop.libcommon.network.model

import kotlin.Exception
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

/**
 * 数据响应封装类
 */
sealed class DataResult<out T> {

    data class Success<out T>(val data: T) : DataResult<T>()

    data class Error(val exception: Exception) : DataResult<Nothing>()

    object Empty: DataResult<Nothing>()

    object Loading : DataResult<Nothing>()

    override fun toString(): String {
        return when(this){
            is Success<*> -> "Success[data = $data]"
            is Error -> "Error[data = $exception]"
            is Empty -> "Empty"
            is Loading -> "Loading"
        }
    }
}

/**
 * 接口返回数据是Success类型且data不为空，才认为是成功的
 */
val DataResult<*>.succeeded
get() = this is DataResult.Success && data != null

/**
 * 扩展用于处理网络返回数据结果 网络接口请求成功，但是业务成功与否，另一说
 */
@OptIn(ExperimentalContracts::class)
inline fun <R> DataResult<R>.onSuccess(
    action: R.() -> Unit
): DataResult<R> {
    contract {
        callsInPlace(action, InvocationKind.AT_MOST_ONCE)
    }
    if (succeeded) action.invoke((this as DataResult.Success<R>).data)
    return this
}

/**
 * 这是网络请求出现错误的时候，的回调
 */
@OptIn(ExperimentalContracts::class)
inline fun <R> DataResult<R>.onFailure(
    action: (exception: Exception) -> Unit
): DataResult<R> {
    contract {
        callsInPlace(action, InvocationKind.AT_MOST_ONCE)
    }
    if (this is DataResult.Error) {
        action.invoke(exception)
    }
    return this
}